// LemCoop
// Copyright (C) 2013  Oliver Naumann <bldrax@gmail.com>

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

#ifndef LEMC_RAKNETCLIENT_H
#define LEMC_RAKNETCLIENT_H

#include <RakPeerInterface.h>
#include <MessageIdentifiers.h>
#include <RakNetTypes.h>
#include <thread>
#include <string>
#include <iostream>
#include <chrono>

#include "job.h"
#include "workmanager.h"

/*
* A low level client for network communication.
*/
class RakNetClient
{
private:
	// Current status of the connection, based on the ConnectionStatus enum.
	char m_connection_status;

	// True if the client is to shut down.
	bool m_shutdown;

	// Number of threads that have yet to finish before we can shutdown.
	int m_threads_to_shutdown;

	// Mutex for shutdown variable.
	std::mutex m_shutdown_mutex;

	// The peer.
	RakNet::RakPeerInterface* m_peer;

	// Guid of the server. This is only filled in once connected.
	RakNet::RakNetGUID m_server_guid;

	// The work manager from/to which jobs are read/saved.
	WorkManager m_work_manager;

	/*
	* Starts the receive thread and constantly receives messages in order to translate them into their respective
	* jobs.
	*/
	void DoReceive();

	/*
	* Starts the send thread and constantly sends messages when jobs are in the queue.
	*/
	void DoSend();

public:
	// Define the status that a connection can have.
	enum ConnectionStatus
	{
		NO_CONNECT = 0,
		PENDING,
		CONNECTED
	};

	/*
	* Sets up the client so that it is ready to connect.
	*/
	RakNetClient();
	~RakNetClient();

	/*
	* Connects to a server on a certain port.
	*
	* @param host The host to connect to.
	* @param port The port to establish the connection on.
	*/
	void Connect(const char* host, unsigned short port);

	/*
	* Shuts down the client and its threads.
	*/
	void Shutdown();

	std::string GetGUID() { return m_peer->GetMyGUID().ToString(); }

	char connection_status() { return m_connection_status; }
	WorkManager* work_manager() { return &m_work_manager; }
};

#endif;